DPOS介绍
概念
Delegated Proof of Stake,委任权益证明。
中文名叫做股份授权证明机制(又称受托人机制),它的原理是让每一个持有比特股的人进行投票,由此产生101位代表 , 我们可以将其理解为101个超级节点或者矿池,而这101个超级节点彼此的权利是完全相等的。从某种角度来看,DPOS有点像是议会制度或人民代表大会制度。如果代表不能履行他们的职责(当轮到他们时,没能生成区块),他们会被除名,网络会选出新的超级节点来取代他们。DPOS的出现最主要还是因为矿机的产生,大量的算力在不了解也不关心比特币的人身上,类似演唱会的黄牛,大量囤票而丝毫不关心演唱会的内容。
比特股引入了见证人这个概念,见证人可以生成区块,每一个持有比特股的人都可以投票选举见证人。得到总同意票数中的前N个(N通常定义为101)候选者可以当选为见证人,当选见证人的个数(N)需满足:至少一半的参与投票者相信N已经充分地去中心化。
见证人的候选名单每个维护周期(1天)更新一次。见证人然后随机排列,每个见证人按序有2秒的权限时间生成区块,若见证人在给定的时间片不能生成区块,区块生成权限交给下一个时间片对应的见证人。DPoS的这种设计使得区块的生成更为快速,也更加节能。
DPoS充分利用了持股人的投票,以公平民主的方式达成共识,他们投票选出的N个见证人,可以视为N个矿池,而这N个矿池彼此的权利是完全相等的。持股人可以随时通过投票更换这些见证人(矿池),只要他们提供的算力不稳定,计算机宕机,或者试图利用手中的权力作恶。
应用
- 比特股 Bitshares(提出这个概念)
- EOS
共识算法我DPoS + BFT
- Asch
共识算法为DPoS + PBFT, 有101个受托人, 目前正在开放竞选
go实现DPOS
案例1
package main
import (
"time"
"encoding/hex"
"math/rand"
"log"
"sort"
"crypto/sha256"
)
//定义区块结构体
type Block struct {
Index int
Timestamp string
BPM int
Hash string
PrevHash string
Delegate string
}
// 创建区块函数
func generateBlock(oldBlock Block, _BMP int, address string) (Block, error) {
var newBlock Block
t := time.Now()
newBlock.Index = oldBlock.Index + 1
newBlock.Timestamp = t.String()
newBlock.BPM = _BMP
newBlock.PrevHash = oldBlock.Hash
newBlock.Hash = createBlockHash(newBlock)
newBlock.Delegate = address
return newBlock, nil
}
//生成区块hash
func createBlockHash(block Block) string {
record := string(block.Index) + block.Timestamp + string(block.BPM) + block.PrevHash
sha3 := sha256.New()
sha3.Write([] byte(record))
hash := sha3.Sum(nil)
return hex.EncodeToString(hash)
}
// 简单的检验区块函数
func isBlockValid(newBlock, oldBlock Block) bool{
if oldBlock.Index + 1 != newBlock.Index {
return false
}
if newBlock.PrevHash != oldBlock.Hash {
return false
}
return true
}
// 区块集合
var blockChain []Block
// dpos里的超级节点结构体(受托人)
type Trustee struct {
name string
votes int
}
type trusteeList [] Trustee
// 下面的三个函数是为了排序使用,大家可以查下go的排序还是很强大的
func (_trusteeList trusteeList) Len() int {
return len(_trusteeList)
}
func (_trusteeList trusteeList) Swap(i, j int){
_trusteeList[i], _trusteeList[j] = _trusteeList[j], _trusteeList[i]
}
func (_trusteeList trusteeList) Less(i, j int) bool {
return _trusteeList[j].votes < _trusteeList[i].votes
}
// 选举获得投票数最高的前5节点作为超级节点,并打乱其顺序
func selectTrustee() ([]Trustee){
_trusteeList := [] Trustee {
{"node1", rand.Intn(100)},
{"node2", rand.Intn(100)},
{"node3", rand.Intn(100)},
{"node4", rand.Intn(100)},
{"node5", rand.Intn(100)},
{"node6", rand.Intn(100)},
{"node7", rand.Intn(100)},
{"node8", rand.Intn(100)},
{"node9", rand.Intn(100)},
{"node10", rand.Intn(100)},
{"node11", rand.Intn(100)},
{"node12", rand.Intn(100)},
}
sort.Sort(trusteeList(_trusteeList))
result := _trusteeList[:5]
_trusteeList = result[1:]
_trusteeList = append(_trusteeList, result[0])
log.Println("当前超级节点列表是", _trusteeList)
return _trusteeList
}
func main() {
t := time.Now()
// init gensis block(创建创世块,真正的可不是这么简单的,这里只做流程实现)
genesisBlock := Block{0, t.String(), 0, createBlockHash(Block{}), "", ""}
blockChain = append(blockChain, genesisBlock) // 这里只是完成了一次dpos的写区块操作,eos真正的是每个节点实现6个区块,并且所有超级节点(21个)轮完,之后再做选举
var trustee Trustee
for _, trustee = range selectTrustee() {
_BPM := rand.Intn(100)
blockHeight := len(blockChain)
oldBlock := blockChain[blockHeight - 1]
newBlock, err := generateBlock(oldBlock, _BPM, trustee.name)
if err != nil {
log.Println(err)
continue
}
if isBlockValid(newBlock, oldBlock) {
blockChain = append(blockChain, newBlock)
log.Println("当前操作区块的节点是: ", trustee.name)
log.Println("当前区块数量是: ", len(blockChain) - 1)
log.Println("当前区块信息: ", blockChain[len(blockChain) - 1])
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。